// Loading and compiling compute shader
// http://msdn.microsoft.com/en-us/library/windows/desktop/ff476330(v=vs.85).aspx
// date accessed: 26/06/2013

#include "ComputeShader.h"
#include "ScreenManager.h"
#include "StringUtilities.h"
#include "TestCSBuffer.h"
#include "ComputeShaderObjectsCB.h"
#include "DX11HelpfulFunctions.h"
#include "DX11ShaderManager.h"
#include "Timer.h"
#include "DX11TextureManager.h"
#include "CameraManager.h"

#include "DXUT.h"
#include <iostream>
#include <d3d11.h>
#include <d3dcompiler.h>
#include <D3DX11.h>

ComputeShader::ComputeShader()
{
	m_computeShader = nullptr;
	m_uavTexture = nullptr;
	m_inputDataBuffer = nullptr;
	m_objectsSRV = nullptr;
	m_textureBuffer = nullptr;
	m_srvTexture = nullptr;
	m_debugBuffer = nullptr;
	m_debugUAV = nullptr;

	m_screenX = TheScreenManager::Instance()->GetWindowWidth();
	m_screenY = TheScreenManager::Instance()->GetWindowHeight();
}

ComputeShader::~ComputeShader()
{
	if (m_computeShader) m_computeShader->Release();
	if (m_uavTexture) m_uavTexture->Release();
	if (m_inputDataBuffer) m_inputDataBuffer->Release();
	if (m_objectsSRV) m_objectsSRV->Release();
	if (m_srvTexture) m_srvTexture->Release();
	if (m_textureBuffer) m_textureBuffer->Release();
	if (m_debugBuffer) m_debugBuffer->Release();
	if (m_debugUAV) m_debugUAV->Release();
}

HRESULT CreateStructuredBuffer( ID3D11Device* pDevice, UINT uElementSize, UINT uCount, VOID* pInitData, ID3D11Buffer** ppBufOut )
{
	*ppBufOut = NULL;

	D3D11_BUFFER_DESC desc;
	ZeroMemory( &desc, sizeof(desc) );
	desc.BindFlags = D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE;
	desc.ByteWidth = uElementSize * uCount;
	desc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;
	desc.StructureByteStride = uElementSize;

	if ( pInitData )
	{
		D3D11_SUBRESOURCE_DATA InitData;
		InitData.pSysMem = pInitData;
		return pDevice->CreateBuffer( &desc, &InitData, ppBufOut );
	} else
		return pDevice->CreateBuffer( &desc, NULL, ppBufOut );
}

HRESULT FindDXSDKShaderFileCch( __in_ecount(cchDest) WCHAR* strDestPath,
                                int cchDest, 
                                __in LPCWSTR strFilename )
{
	
    if( NULL == strFilename || strFilename[0] == 0 || NULL == strDestPath || cchDest < 10 )
        return E_INVALIDARG;

    // Get the exe name, and exe path
    WCHAR strExePath[MAX_PATH] =
    {
        0
    };
    WCHAR strExeName[MAX_PATH] =
    {
        0
    };
    WCHAR* strLastSlash = NULL;
    GetModuleFileName( NULL, strExePath, MAX_PATH );
    strExePath[MAX_PATH - 1] = 0;
    strLastSlash = wcsrchr( strExePath, TEXT( '\\' ) );
    if( strLastSlash )
    {
        wcscpy_s( strExeName, MAX_PATH, &strLastSlash[1] );

        // Chop the exe name from the exe path
        *strLastSlash = 0;

        // Chop the .exe from the exe name
        strLastSlash = wcsrchr( strExeName, TEXT( '.' ) );
        if( strLastSlash )
            *strLastSlash = 0;
    }

    // Search in directories:
    //      .\
    //      %EXE_DIR%\..\..\%EXE_NAME%

    wcscpy_s( strDestPath, cchDest, strFilename );
    if( GetFileAttributes( strDestPath ) != 0xFFFFFFFF )
        return true;

    swprintf_s( strDestPath, cchDest, L"%s\\..\\..\\%s\\%s", strExePath, strExeName, strFilename );
    if( GetFileAttributes( strDestPath ) != 0xFFFFFFFF )
        return true;    

    // On failure, return the file as the path but also return an error code
    wcscpy_s( strDestPath, cchDest, strFilename );

    return E_FAIL;
}

HRESULT CompileComputeShader( LPCWSTR pSrcFile, LPCSTR pFunctionName, 
							 ID3D11Device* pDevice, ID3D11ComputeShader** ppShaderOut )
{
	HRESULT hr;

	std::cout << *pSrcFile << std::endl;
	std::cout << pFunctionName << std::endl;

	// Finds the correct path for the shader file.
	// This is only required for this sample to be run correctly from within the Sample Browser,
	// in your own projects, these lines could be removed safely
	//WCHAR str[MAX_PATH];
	//hr = FindDXSDKShaderFileCch( str, MAX_PATH, pSrcFile );
	//if ( FAILED(hr) )
	//	return hr;

	DWORD dwShaderFlags = D3DCOMPILE_ENABLE_STRICTNESS;
#if defined( DEBUG ) || defined( _DEBUG )
	// Set the D3DCOMPILE_DEBUG flag to embed debug information in the shaders.
	// Setting this flag improves the shader debugging experience, but still allows 
	// the shaders to be optimized and to run exactly the way they will run in 
	// the release configuration of this program.
	dwShaderFlags |= D3DCOMPILE_DEBUG;
#endif

	const D3D_SHADER_MACRO defines[] = 
	{
#ifdef USE_STRUCTURED_BUFFERS
		"USE_STRUCTURED_BUFFERS", "1",
#endif

#ifdef TEST_DOUBLE
		"TEST_DOUBLE", "1",
#endif
		NULL, NULL
	};

	// We generally prefer to use the higher CS shader profile when possible as CS 5.0 is better performance on 11-class hardware
	LPCSTR pProfile = ( pDevice->GetFeatureLevel() >= D3D_FEATURE_LEVEL_11_0 ) ? "cs_5_0" : "cs_4_0";

	ID3DBlob* pErrorBlob = NULL;
	ID3DBlob* pBlob = NULL;
	//hr = D3DCompileFromFile(pSrcFile, defines, NULL, pFunctionName, pProfile, dwShaderFlags, NULL, NULL, &pErrorBlob);
	hr = D3DX11CompileFromFile( pSrcFile, defines, NULL, pFunctionName, pProfile, 
		dwShaderFlags, NULL, NULL, &pBlob, &pErrorBlob, NULL );
	if ( FAILED(hr) )
	{
		std::cout << "Failed to compile compute shader from file" << std::endl;

		if ( pErrorBlob )
			OutputDebugStringA( (char*)pErrorBlob->GetBufferPointer() );

		if (pErrorBlob) pErrorBlob->Release();
		if (pBlob) pBlob->Release();    

		return hr;
	}    

	hr = pDevice->CreateComputeShader( pBlob->GetBufferPointer(), pBlob->GetBufferSize(), NULL, ppShaderOut );

#if defined(DEBUG) || defined(PROFILE)
	if ( *ppShaderOut )
		(*ppShaderOut)->SetPrivateData( WKPDID_D3DDebugObjectName, lstrlenA(pFunctionName), pFunctionName );
#endif

	if (pErrorBlob) pErrorBlob->Release();
	if (pBlob) pBlob->Release();;

	return hr;
}

HRESULT ComputeShader::CompileShader(_In_ const std::string& filename, _In_ const std::string& functionName,
									 _In_ ID3D11Device* device, _Outptr_ ID3DBlob** blob)
{
	std::wstring srcFile = std::wstring(filename.begin(), filename.end()).c_str();
	LPCSTR entryPoint =  functionName.c_str();

	if ( srcFile.empty() || !entryPoint || !device || !blob )
		return E_INVALIDARG;

	*blob = nullptr;

	UINT flags = D3DCOMPILE_ENABLE_STRICTNESS;
#if defined( DEBUG ) || defined( _DEBUG )
	flags |= D3DCOMPILE_DEBUG;
#endif

	// We generally prefer to use the higher CS shader profile when possible as CS 5.0 is better performance on 11-class hardware
	LPCSTR profile = ( device->GetFeatureLevel() >= D3D_FEATURE_LEVEL_11_0 ) ? "cs_5_0" : "cs_4_0";

	const D3D_SHADER_MACRO defines[] = 
	{
		"EXAMPLE_DEFINE", "1",
		NULL, NULL
	};

	ID3DBlob* shaderBlob = nullptr;
	ID3DBlob* errorBlob = nullptr;
	//HRESULT hr = D3DCompileFromFile( srcFile, defines, D3D_COMPILE_STANDARD_FILE_INCLUDE,
	//                                 entryPoint, profile,
	//                                 flags, 0, &shaderBlob, &errorBlob );

	HRESULT hr = CompileComputeShader(srcFile.c_str(), entryPoint, TheScreenManager::Instance()->GetDevice(), &m_computeShader);

	if ( FAILED(hr) )
	{
		if ( errorBlob )
		{
			OutputDebugStringA( (char*)errorBlob->GetBufferPointer() );
			errorBlob->Release();
		}

		if ( shaderBlob )
			shaderBlob->Release();

		return hr;
	}    

	*blob = shaderBlob;

	return hr;
}

HRESULT CreateBufferSRV( ID3D11Device* pDevice, ID3D11Buffer* pBuffer, ID3D11ShaderResourceView** ppSRVOut )
{
    D3D11_BUFFER_DESC descBuf;
    ZeroMemory( &descBuf, sizeof(descBuf) );
    pBuffer->GetDesc( &descBuf );

    D3D11_SHADER_RESOURCE_VIEW_DESC desc;
    ZeroMemory( &desc, sizeof(desc) );
    desc.ViewDimension = D3D11_SRV_DIMENSION_BUFFEREX;
    desc.BufferEx.FirstElement = 0;

    if ( descBuf.MiscFlags & D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS )
    {
        // This is a Raw Buffer

        desc.Format = DXGI_FORMAT_R32_TYPELESS;
        desc.BufferEx.Flags = D3D11_BUFFEREX_SRV_FLAG_RAW;
        desc.BufferEx.NumElements = descBuf.ByteWidth / 4;
    } else
    if ( descBuf.MiscFlags & D3D11_RESOURCE_MISC_BUFFER_STRUCTURED )
    {
        // This is a Structured Buffer

        desc.Format = DXGI_FORMAT_UNKNOWN;
        desc.BufferEx.NumElements = descBuf.ByteWidth / descBuf.StructureByteStride;
    } else
    {
        return E_INVALIDARG;
    }

    return pDevice->CreateShaderResourceView( pBuffer, &desc, ppSRVOut );
}

HRESULT CreateBufferUAV( ID3D11Device* pDevice, ID3D11Buffer* pBuffer, ID3D11UnorderedAccessView** ppUAVOut )
{
    D3D11_BUFFER_DESC descBuf;
    ZeroMemory( &descBuf, sizeof(descBuf) );
    pBuffer->GetDesc( &descBuf );
        
    D3D11_UNORDERED_ACCESS_VIEW_DESC desc;
    ZeroMemory( &desc, sizeof(desc) );
    desc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
    desc.Buffer.FirstElement = 0;

    if ( descBuf.MiscFlags & D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS )
    {
        // This is a Raw Buffer

        desc.Format = DXGI_FORMAT_R32_TYPELESS; // Format must be DXGI_FORMAT_R32_TYPELESS, when creating Raw Unordered Access View
        desc.Buffer.Flags = D3D11_BUFFER_UAV_FLAG_RAW;
        desc.Buffer.NumElements = descBuf.ByteWidth / 4; 
    } else
    if ( descBuf.MiscFlags & D3D11_RESOURCE_MISC_BUFFER_STRUCTURED )
    {
        // This is a Structured Buffer

        desc.Format = DXGI_FORMAT_UNKNOWN;      // Format must be must be DXGI_FORMAT_UNKNOWN, when creating a View of a Structured Buffer
        desc.Buffer.NumElements = descBuf.ByteWidth / descBuf.StructureByteStride; 
    } else
    {
        return E_INVALIDARG;
    }
    
    return pDevice->CreateUnorderedAccessView( pBuffer, &desc, ppUAVOut );
}

void RunComputeShader( ID3D11DeviceContext* pd3dImmediateContext,
                      ID3D11ComputeShader* pComputeShader,
                      UINT nNumViews, ID3D11ShaderResourceView** pShaderResourceViews, 
                      ID3D11Buffer* pCBCS, void* pCSData, DWORD dwNumDataBytes,
                      ID3D11UnorderedAccessView* pUnorderedAccessView,
                      UINT X, UINT Y, UINT Z )
{
    pd3dImmediateContext->CSSetShader( pComputeShader, NULL, 0 );
    pd3dImmediateContext->CSSetShaderResources( 0, nNumViews, pShaderResourceViews );
    pd3dImmediateContext->CSSetUnorderedAccessViews( 0, 1, &pUnorderedAccessView, NULL );
    if ( pCBCS )
    {
        D3D11_MAPPED_SUBRESOURCE MappedResource;
        pd3dImmediateContext->Map( pCBCS, 0, D3D11_MAP_WRITE_DISCARD, 0, &MappedResource );
        memcpy( MappedResource.pData, pCSData, dwNumDataBytes );
        pd3dImmediateContext->Unmap( pCBCS, 0 );
        ID3D11Buffer* ppCB[1] = { pCBCS };
        pd3dImmediateContext->CSSetConstantBuffers( 0, 1, ppCB );
    }

	pd3dImmediateContext->Dispatch(TheScreenManager::Instance()->GetWindowWidth(), TheScreenManager::Instance()->GetWindowHeight(), 1);

    pd3dImmediateContext->CSSetShader( NULL, NULL, 0 );

    ID3D11UnorderedAccessView* ppUAViewNULL[1] = { NULL };
    pd3dImmediateContext->CSSetUnorderedAccessViews( 0, 1, ppUAViewNULL, NULL );

    ID3D11ShaderResourceView* ppSRVNULL[2] = { NULL, NULL };
    pd3dImmediateContext->CSSetShaderResources( 0, 2, ppSRVNULL );

    ID3D11Buffer* ppCBNULL[1] = { NULL };
    pd3dImmediateContext->CSSetConstantBuffers( 0, 1, ppCBNULL );
}

ID3D11Buffer* CreateAndCopyToDebugBuffer( ID3D11Device* pDevice, ID3D11DeviceContext* pd3dImmediateContext, ID3D11Buffer* pBuffer )
{
    ID3D11Buffer* debugbuf = NULL;

    D3D11_BUFFER_DESC desc;
    ZeroMemory( &desc, sizeof(desc) );
    pBuffer->GetDesc( &desc );
    desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
    desc.Usage = D3D11_USAGE_STAGING;
    desc.BindFlags = 0;
    desc.MiscFlags = 0;
    if ( SUCCEEDED(pDevice->CreateBuffer(&desc, NULL, &debugbuf)) )
    {
#if defined(DEBUG) || defined(PROFILE)
        debugbuf->SetPrivateData( WKPDID_D3DDebugObjectName, sizeof( "Debug" ) - 1, "Debug" );
#endif

        pd3dImmediateContext->CopyResource( debugbuf, pBuffer );
    }

    return debugbuf;
}

const int NUM_OF_ELEMENTS = 4;

bool ComputeShader::Load(const std::string& filename)
{
	HRESULT hr = S_OK;
	CSBuffer inputDataBuffer;

	ID3DBlob* blob = nullptr;
	hr = CompileShader(filename, "main", TheScreenManager::Instance()->GetDevice(), &blob);
	if (blob) blob->Release();
	
	D3D11_TEXTURE2D_DESC texDesc;
	texDesc.Width = m_screenX;
	texDesc.Height = m_screenY;
	texDesc.MipLevels = 1;
	texDesc.ArraySize = 1;
	texDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
	texDesc.SampleDesc.Count   = 1;
	texDesc.SampleDesc.Quality = 0;
	texDesc.Usage = D3D11_USAGE_DEFAULT;
	texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS;
	texDesc.CPUAccessFlags = 0;
	texDesc.MiscFlags = 0;

	ID3D11Texture2D* texture = nullptr;
	hr = TheScreenManager::Instance()->GetDevice()->CreateTexture2D(&texDesc, nullptr, &texture);

	D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
	srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
	srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
	srvDesc.Texture2D.MostDetailedMip = 0;
	srvDesc.Texture2D.MipLevels = 1;
	hr = TheScreenManager::Instance()->GetDevice()->CreateShaderResourceView(texture, &srvDesc, &m_srvTexture);

	D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc;
	uavDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
	uavDesc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2D;
	uavDesc.Texture2D.MipSlice = 0;
	hr = TheScreenManager::Instance()->GetDevice()->CreateUnorderedAccessView(texture, &uavDesc, &m_uavTexture);
	
	CSDebugBuffer debugBufferResults;
	CreateStructuredBuffer(TheScreenManager::Instance()->GetDevice(), sizeof(CSDebugBuffer), 1, &debugBufferResults, &m_debugBuffer);
	CreateBufferUAV(TheScreenManager::Instance()->GetDevice(), m_debugBuffer, &m_debugUAV);

	// init camera
	Vec3f camPosition(0.0f, 1.5f, -10.0f);
	Vec3f camLookAt(0.0f, 0.0f, 0.0f);
	Vec3f camDirection = camLookAt - camPosition;
	camDirection.Normalise();

	Vec3f camRight;
	Vec3f camDown;
	camRight.CrossProduct(Vec3f(0.0f, 1.0f, 0.0f), camDirection);
	camRight.Normalise();
	camDown.CrossProduct(camRight, camDirection);

	CSCamera camera(camPosition, camDirection, camRight, camDown);
	inputDataBuffer.camera = camera;


	// create the objects buffer
	CSObjects objects;
	objects.spheres[0].position = Vec3f(-1.75f, 0.25f, 0.0f);
	objects.spheres[0].radius = 0.5f;
	objects.spheres[0].colour = CSColour(0.8f, 0.8f, 0.0f, 1.0f);
	objects.spheres[0].colour.gloss = 0.3f;
	objects.spheres[1].position = Vec3f(1.75f, 0.25f, 0.0f);
	objects.spheres[1].radius = 0.5f;
	objects.spheres[1].colour = CSColour(0.0f, 0.8f, 0.8f, 1.0f);
	objects.spheres[1].colour.gloss = 0.3f;
	CSTriangle tri(Vec3f(2.0f, -0.5, 0.0f), Vec3f(0.0f, 1.0f, 0.0f), Vec3f(-2.0f, -0.5f, -2.0f), CSColour(0.2, 0.8, 0.8, 1.0));
	objects.triangles[0] = tri;
	objects.triangles[0].colour.gloss = 0.3f;
	CSTriangle tri2(Vec3f(-2.0f, -0.5, 0.0f), Vec3f(0.0f, 1.0f, 0.0f), Vec3f(-2.0f, -0.5f, -2.0f), CSColour(0.8, 0.2, 0.8, 1.0));
	objects.triangles[1] = tri2;
	objects.triangles[1].colour.gloss = 0.3f;




	inputDataBuffer.objects = objects;
	

	// init lights
	CSLight light;
	light.position = Vec3f(-7.0f, 10.0f, -10.0f);
	light.colour = CSColour(1.0f, 1.0f, 1.0f, 1.0f);

	inputDataBuffer.light = light;
	
	D3D11_BUFFER_DESC desc;
	ZeroMemory( &desc, sizeof(desc) );
	desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
	desc.ByteWidth = sizeof(CSBuffer);
	desc.MiscFlags = 0;
	desc.StructureByteStride = sizeof(CSBuffer);
	desc.Usage = D3D11_USAGE_DEFAULT;
	
	D3D11_SUBRESOURCE_DATA initData;
	initData.pSysMem = &inputDataBuffer;
	hr = TheScreenManager::Instance()->GetDevice()->CreateBuffer(&desc, &initData, &m_inputDataBuffer);


	//CreateStructuredBuffer(TheScreenManager::Instance()->GetDevice(), sizeof(CSBuffer), 1, &inputDataBuffer, &m_inputDataBuffer);
	
	//	
	//TheScreenManager::Instance()->GetDeviceContext()->CSSetShader(m_computeShader, nullptr, 0);
	//ID3D11UnorderedAccessView* UAVs[] = {m_uavTexture, m_debugUAV};
	//TheScreenManager::Instance()->GetDeviceContext()->CSSetUnorderedAccessViews(0, 2, UAVs, nullptr);
	//ID3D11ShaderResourceView* shaderResourceViews[] = {m_srvTexture};
 //   TheScreenManager::Instance()->GetDeviceContext()->CSSetShaderResources( 0, 1, shaderResourceViews);
	//TheScreenManager::Instance()->GetDeviceContext()->CSSetConstantBuffers(0, 1, &m_inputDataBuffer);

	//TheScreenManager::Instance()->GetDeviceContext()->Dispatch(m_screenX, m_screenY, 1);
	//
	//ID3D11ComputeShader* nullCs = nullptr;
	//TheScreenManager::Instance()->GetDeviceContext()->CSSetShader(nullCs, nullptr, 0);
	//ID3D11ShaderResourceView* nullView = nullptr;
	//TheScreenManager::Instance()->GetDeviceContext()->CSSetShaderResources(0, 1, &nullView);
	//ID3D11UnorderedAccessView* nullUav[] = {nullptr, nullptr};
	//TheScreenManager::Instance()->GetDeviceContext()->CSSetUnorderedAccessViews(0, 2, nullUav, (UINT*)(&nullUav));
	//ID3D11Buffer* nullbuffer = nullptr;
	//TheScreenManager::Instance()->GetDeviceContext()->CSSetConstantBuffers(0, 1, &nullbuffer);

	//// check debug results
	//ID3D11Buffer* results = CreateAndCopyToDebugBuffer(TheScreenManager::Instance()->GetDevice(), TheScreenManager::Instance()->GetDeviceContext(), m_debugBuffer);
	//D3D11_MAPPED_SUBRESOURCE mapped;
	//CSDebugBuffer* resultsData;
	//TheScreenManager::Instance()->GetDeviceContext()->Map(results, 0, D3D11_MAP_READ, 0, &mapped);

	//resultsData = (CSDebugBuffer*)mapped.pData;

	//TheScreenManager::Instance()->GetDeviceContext()->Unmap(results, 0);

	//
	//DX11::ClearColour(0.0f, 0.0f, 0.7f, 1.0f);
	//D3DXMATRIX m_view;
	//D3DXMATRIX m_proj;

	//D3DXMatrixLookAtLH(&m_view, &D3DXVECTOR3(0.0f, 0.0f, 1.0f), 
	//	&D3DXVECTOR3(0.0f, 0.0f, 0.0f), 
	//	&D3DXVECTOR3(0.0f, 1.0f, 0.0f));
	//
	//D3DXMatrixOrthoLH(&m_proj, float(m_screenX), float(m_screenY), 0, 100);

	//TheScreenManager::Instance()->SetViewProjMatrix(m_view, m_proj);
	//	
	//TheObjMeshManager::Instance()->Scale("quad", D3DXVECTOR3(float(m_screenX), float(m_screenY), 1.0f));
	////TheObjMeshManager::Instance()->ChangeTexture("quad",
	////	TheDX11TextureManager::Instance()->UseTexture(L"../../Assets/title_image.png"));
	//TheObjMeshManager::Instance()->ChangeTexture("quad", m_srvTexture);
	//TheObjMeshManager::Instance()->Draw("quad");

	//TheScreenManager::Instance()->FlipBuffers();
	//TheScreenManager::Instance()->FlipBuffers();




	if (FAILED(hr))
	{
		return false;
	}
	return true;
}

void ComputeShader::Run()
{
	
	CSBuffer inputDataBuffer;

	// init camera
	//Vec3f camPosition(0.0f, 1.5f, -10.0f);
	//Vec3f camLookAt(0.0f, 0.0f, 0.0f);
	//Vec3f camDirection = camLookAt - camPosition;
	//camDirection.Normalise();

	//Vec3f camRight;
	//Vec3f camDown;
	//camRight.CrossProduct(Vec3f(0.0f, 1.0f, 0.0f), camDirection);
	//camRight.Normalise();
	//camDown.CrossProduct(camRight, camDirection);

	//CSCamera camera(camPosition, camDirection, camRight, camDown);
	//inputDataBuffer.camera = camera;
	
	inputDataBuffer.camera = TheCameraManager::Instance()->GetCamera();

	
	static float lightColR = 1.0f;
	static float lightPosX = 0.25f;
	static float sinPheta = 0.0f;
	static float time = 0.0f;
	float dt = TheTimer::Instance()->GetDt();
	
	static float planeSize = 4.0f;
	static float planeY = -0.5f;

	// create the objects buffer
	CSObjects objects;
	objects.spheres[0].position = Vec3f(-1.75f, 0.25f, 0.0f);
	objects.spheres[0].radius = 0.5f;
	objects.spheres[0].colour = CSColour(0.8f, 0.8f, 0.0f, 1.0f);
	objects.spheres[0].colour.gloss = 0.3f;
	objects.spheres[1].position = Vec3f(1.75f, 0.25f, 0.0f);
	objects.spheres[1].radius = 0.5f;
	objects.spheres[1].colour = CSColour(0.0f, 0.8f, 0.8f, 1.0f);
	objects.spheres[1].colour.gloss = 0.3f;
	CSTriangle tri(Vec3f(-planeSize, planeY, -planeSize), Vec3f(planeSize, planeY, -planeSize), Vec3f(planeSize, planeY, planeSize), 
					CSColour(0.8, 0.2, 0.8, 1.0));
	objects.triangles[0] = tri;
	objects.triangles[0].colour.gloss = 0.3f;
	CSTriangle tri2(Vec3f(planeSize, planeY, planeSize), Vec3f(-planeSize, planeY, planeSize), Vec3f(-planeSize, planeY, -planeSize), 
					CSColour(0.8, 0.2, 0.8, 1.0));
	objects.triangles[1] = tri2;
	objects.triangles[1].colour.gloss = 0.3f;
	inputDataBuffer.objects = objects;

	// init lights
	CSLight light;
	//light.position = Vec3f(sin(sinPheta) * 5.0f, 5.0f, cos(sinPheta) * 5.0f);
	light.position = Vec3f(10.0f, 10.0f, -2.0f);
	light.colour = CSColour(lightColR, 1.0f, 1.0f, 1.0f);

	time += dt;
	if (time > 0.01f)
	{
		time = 0.0f;
		sinPheta += 0.01f;
		lightPosX += 0.01f;
	}

	//inputDataBuffer.camera = TheCameraManager::Instance()->GetCamera();

	inputDataBuffer.light = light;
	TheScreenManager::Instance()->GetDeviceContext()->UpdateSubresource(m_inputDataBuffer, 0, nullptr, &inputDataBuffer, 0, 0);


	TheScreenManager::Instance()->GetDeviceContext()->CSSetShader(m_computeShader, nullptr, 0);
	ID3D11UnorderedAccessView* UAVs[] = {m_uavTexture, m_debugUAV};
	TheScreenManager::Instance()->GetDeviceContext()->CSSetUnorderedAccessViews(0, 2, UAVs, nullptr);
	ID3D11ShaderResourceView* shaderResourceViews[] = {m_srvTexture};
    TheScreenManager::Instance()->GetDeviceContext()->CSSetShaderResources( 0, 1, shaderResourceViews);
	TheScreenManager::Instance()->GetDeviceContext()->CSSetConstantBuffers(0, 1, &m_inputDataBuffer);

	TheScreenManager::Instance()->GetDeviceContext()->Dispatch(m_screenX, m_screenY, 1);
	
	ID3D11ComputeShader* nullCs = nullptr;
	TheScreenManager::Instance()->GetDeviceContext()->CSSetShader(nullCs, nullptr, 0);
	ID3D11ShaderResourceView* nullView = nullptr;
	TheScreenManager::Instance()->GetDeviceContext()->CSSetShaderResources(0, 1, &nullView);
	ID3D11UnorderedAccessView* nullUav[] = {nullptr, nullptr};
	TheScreenManager::Instance()->GetDeviceContext()->CSSetUnorderedAccessViews(0, 2, nullUav, (UINT*)(&nullUav));
	ID3D11Buffer* nullbuffer = nullptr;
	TheScreenManager::Instance()->GetDeviceContext()->CSSetConstantBuffers(0, 1, &nullbuffer);
	
	//// check debug results
	ID3D11Buffer* results = CreateAndCopyToDebugBuffer(TheScreenManager::Instance()->GetDevice(), TheScreenManager::Instance()->GetDeviceContext(), m_debugBuffer);
	D3D11_MAPPED_SUBRESOURCE mapped;
	CSDebugBuffer* resultsData;
	TheScreenManager::Instance()->GetDeviceContext()->Map(results, 0, D3D11_MAP_READ, 0, &mapped);

	resultsData = (CSDebugBuffer*)mapped.pData;

	TheScreenManager::Instance()->GetDeviceContext()->Unmap(results, 0);

	TheObjMeshManager::Instance()->Scale("quad", D3DXVECTOR3(float(m_screenX), float(m_screenY), 1.0f));
	TheObjMeshManager::Instance()->ChangeTexture("quad", m_srvTexture);
	TheObjMeshManager::Instance()->Draw("quad");
}

ID3D11ShaderResourceView* ComputeShader::GetResult()
{
	return m_srvTexture;
}